var mosca = require('mosca');
var amqp = require('amqp');
var crypto = require('crypto');
var path = require('path');
var log4js = require('../utils/logger');
var config = require('../config');

var Logger = log4js.getLogger(path.basename(__filename));
Logger.setLevel(config.LogLevel);

var RANDOM_LEN = 10;

var ascoltatore = {
  type: 'amqp',
  json: false,
  amqp: amqp,
  client: amqp.createConnection({ host: 'localhost' }),
  exchange: 'makeblock-iot-topics'
};

var port = 8080;

var moscaSettings = {
  port: port,
  backend: ascoltatore,
  http: {
    port: 1884,
    bundle: true,
    static: './'
  }
};

var authenticate = function(client, username, password, callback) {
  Logger.info('[line:' + __line + ']' + ' authenticate, username:' + username + ',password:' + password);
  var authorized = true;
  if(username == undefined || password == undefined) {
    //todo
    Logger.error('[line:' + __line + ']' + ' unexpected case: username or password is undefined');
  } else {
    if(username == 'makeblockiot' && password.toString() == 'makeiotblock') {
      Logger.info('[line:' + __line + ']' + ' authorized true');
      authorized = true;
    } else {
      authorized = _decodeUserKey(password.toString());
      Logger.info('[line:' + __line + ']' + ' authorized password:' + password.toString() + ' ' + authorized);
    }
  }

  if (authorized) {
    client.user = username;
  }
  callback(null, authorized);
}

// var authorizePublish = function(client, topic, payload, callback) {
//   console.log('authorizePublish');
//   callback(null, client.user == topic.split('/')[1]);
// }

// var authorizeSubscribe = function(client, topic, callback) {
//   console.log('authorizeSubscribe');
//   callback(null, client.user == topic.split('/')[1]);
// }

var _genRandomString = function(callback) {
  crypto.randomBytes(RANDOM_LEN, (err, buf) => {
    if (err) {
      return callback(err);
    }
    return callback(null, buf.toString('base64'));
  });
};

var _genUserKey = function(id) {
  var cipher = crypto.createCipher('aes192', 'makeblock-shenjingyuan-iot');
    _genRandomString(function(err, str) {
      var encrypted = cipher.update(id + '/' + str, 'utf8', 'hex');
      encrypted += cipher.final('hex');
      Logger.info('[line:' + __line + ']' + ' encrypted:' + encrypted);
      return encrypted;
    });
};

var _decodeUserKey = function(key) {
  var decipher = crypto.createDecipher('aes192', 'makeblock-shenjingyuan-iot');
  var encrypted = key;
  var ok = false;
  var decrypted;
  try {
    decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    Logger.info('[line:' + __line + ']' + ' decrypted:' + decrypted);
    Logger.info('[line:' + __line + ']' + ' userid:' + parseInt(decrypted.split('/')[0]));
    // parseInt(decrypted.split('/')[0]);
    ok = true;
  } catch(e) {
    ok = false;
    Logger.error('[line:' + __line + ']' + ' _decodeUserKey failed');
  }
  return ok;
};

function runServer() {
  var server = new mosca.Server(moscaSettings);
  server.on('ready', setup);

  server.on('clientConnected', function(client) {
    Logger.info('[line:' + __line + ']' + ' connected, clientId:' + client.id);
  });

  // fired when a message is received
  server.on('published', function(packet, client) {
    if (client){
      Logger.info('Received Topic:' + packet.topic + ', payload:' + packet.payload.toString());
    }
    
  });

  // fired when the mqtt server is ready
  function setup() {
    server.authenticate = authenticate;
    // server.authorizePublish = authorizePublish;
    // server.authorizeSubscribe = authorizeSubscribe;
    Logger.info('[line:' + __line + ']' + ' mqtt broker is up and running on port ' + port);
    // _genUserKey(9);
    // var key = '8616b459de4c8ba47f7a3d3d9c1faeeebe50b562900358815059038ad86f87aa';
    // _decodeUserKey(key);
    // _decodeUserKey('shansjlinyanwenhuangyanwen');
  }

  // add websocket support
}

exports.runServer = runServer;
